package com.xinchuang.utils;

import com.alibaba.fastjson.JSONArray;

public class MercatorWmtsUtils {
    /**
     * 瓦片大小
     */
    public final static int TILE_SIZE = 256;

    public static int[] coordinates2tile(double lng, double lat, int zoom) {
        int x = (int) Math.floor((lng + 180) / 360 * (1 << zoom));
        int y = (int) Math.floor((1 - Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI) / 2 * (1 << zoom));
        if (x < 0) {
            x = 0;
        }
        if (x >= (1 << zoom)) {
            x = ((1 << zoom) - 1);
        }
        if (y < 0) {
            y = 0;
        }
        if (y >= (1 << zoom)) {
            y = ((1 << zoom) - 1);
        }
        return new int[]{x, y};
    }

    public static double tile2lng(double x, int z) {
        return x / Math.pow(2.0, z) * 360.0 - 180;
    }

    public static double tile2lat(double y, int z) {
        double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
        return Math.toDegrees(Math.atan(Math.sinh(n)));
    }

    public static String xyzToQuadKey(int tileX, int tileY, int levelOfDetail) {
        StringBuilder quadKey = new StringBuilder();
        for (int i = levelOfDetail; i > 0; i--) {
            char digit = '0';
            int mask = 1 << (i - 1);
            if ((tileX & mask) != 0) {
                digit++;
            }
            if ((tileY & mask) != 0) {
                digit++;
                digit++;
            }
            quadKey.append(digit);
        }
        return quadKey.toString();
    }

    public static int[] quadKeyToXYZ(String quadKey) throws Exception {
        int tileX = 0;
        int tileY = 0;
        int length = quadKey.length();
        for (int i = length; i > 0; i--) {
            int mask = 1 << (i - 1);
            switch (quadKey.charAt(length - i)) {
                case '0':
                    break;
                case '1':
                    tileX |= mask;
                    break;
                case '2':
                    tileY |= mask;
                    break;
                case '3':
                    tileX |= mask;
                    tileY |= mask;
                    break;
                default:
                    throw new Exception("Invalid QuadKey digit sequence.");
            }
        }
        return new int[]{tileX, tileY, length};
    }

    //笛卡尔坐标转经纬度
    //[{"x":-2385687.468728053,"y":5388713.58735659,"z":2431266.178004133},{"x":-2386487.889323949,"y":5388376.532927499,"z":2431227.9203221975},{"x":-2385720.8091358775,"y":5388914.668443492,"z":2430790.9295658045},{"x":-2386030.8053309857,"y":5388422.52348345,"z":2431572.274479368},{"x":-2386549.913805695,"y":5388583.616999787,"z":2430711.4885351057},{"x":-2385867.777372268,"y":5388687.89246894,"z":2431146.993799864}]
    public static String ECEFtoWGS84(double x, double y, double z) {
        double a, b, c, d;
        double Longitude;//经度
        double Latitude;//纬度
        double Altitude;//海拔高度
        double p, q;
        double N;
        a = 6378137.0;
        b = 6356752.31424518;
        c = Math.sqrt(((a * a) - (b * b)) / (a * a));
        d = Math.sqrt(((a * a) - (b * b)) / (b * b));
        p = Math.sqrt((x * x) + (y * y));
        q = Math.atan2((z * a), (p * b));
        Longitude = Math.atan2(y, x);
        Latitude = Math.atan2((z + (d * d) * b * Math.pow(Math.sin(q), 3)), (p - (c * c) * a * Math.pow(Math.cos(q), 3)));
        N = a / Math.sqrt(1 - ((c * c) * Math.pow(Math.sin(Latitude), 2)));
        Altitude = (p / Math.cos(Latitude)) - N;
        Longitude = Longitude * 180.0 / Math.PI;
        Latitude = Latitude * 180.0 / Math.PI;
        //默认海拔高度为0
        return Longitude + "," + Latitude + "," + Altitude + " ";
    }

    public static JSONArray getCutCenterByArr(double minX, double maxX, double minY, double maxY) {
        // 将经度纬度转换为弧度
        double maxLongitudeRad = Math.toRadians(maxX);
        double minLongitudeRad = Math.toRadians(minX);
        double maxLatitudeRad = Math.toRadians(maxY);
        double minLatitudeRad = Math.toRadians(minY);

        // 计算中心点的经度和纬度
        double centerLongitude = (maxLongitudeRad + minLongitudeRad) / 2;
        double centerLatitude = (maxLatitudeRad + minLatitudeRad) / 2;

        // 将中心点的经度和纬度转换为角度
        double centerLongitudeDeg = Math.toDegrees(centerLongitude);
        double centerLatitudeDeg = Math.toDegrees(centerLatitude);

        JSONArray arr = new JSONArray();
        arr.add(centerLongitudeDeg);
        arr.add(centerLatitudeDeg);
        arr.add(200);
        return arr;
    }

    public static void main(String[] args) throws Exception {
        int[] ints = quadKeyToXYZ("13213210310132230");
        for (int anInt : ints) {
            System.out.println(anInt);
        }
        double v = tile2lng(ints[0], ints[2]);
        double v1 = tile2lat(ints[1], ints[2]);
        System.out.println(v + "," + v1);
        String s = xyzToQuadKey(ints[0], ints[1], ints[2]);
        System.out.println(s);

        //3.412297275000528===3.3651808547401028===25.340027949308304===25.307512000463735
        //2.7057126323218017===2.665848238219646===32.17595827169954===32.144217547959144
        double minX = 2.665848238219646;
        double maxX = 2.7057126323218017;
        double minY = 32.144217547959144;
        double maxY = 32.17595827169954;

        // 将经度纬度转换为弧度
        double maxLongitudeRad = Math.toRadians(maxX);
        double minLongitudeRad = Math.toRadians(minX);
        double maxLatitudeRad = Math.toRadians(maxY);
        double minLatitudeRad = Math.toRadians(minY);

        // 计算中心点的经度和纬度
        double centerLongitude = (maxLongitudeRad + minLongitudeRad) / 2;
        double centerLatitude = (maxLatitudeRad + minLatitudeRad) / 2;

        // 将中心点的经度和纬度转换为角度
        double centerLongitudeDeg = Math.toDegrees(centerLongitude);
        double centerLatitudeDeg = Math.toDegrees(centerLatitude);

        System.out.println("中心点的经度：" + centerLongitudeDeg);
        System.out.println("中心点的纬度：" + centerLatitudeDeg);

        int[] tile = coordinates2tile(centerLongitudeDeg, centerLatitudeDeg, 15);
        for (int anInt : tile) {
            System.out.println(anInt);
        }
        s = xyzToQuadKey(tile[0], tile[1], 15);
        System.out.println(s);

        v = tile2lng(tile[0], 15);
        v1 = tile2lat(tile[1], 15);
        System.out.println(v + "," + v1);


        v = tile2lng(827262, 20);
        v1 = tile2lat(520446, 20);
        System.out.println(v + "," + v1);
    }
}
